home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / USBSampleStorageDriver / UnitTableDriver / UnitTableDriveQSupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-25  |  46.1 KB  |  1,623 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        UnitTableDriveQSupport.c
  3.  
  4.     Contains:    All functionality for managing Drive Queue elements. 
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-2000 by Apple Computer, Inc., all rights reserved.
  9.  
  10.  
  11. */
  12. #include <DriverGestalt.h>
  13. #include <Gestalt.h>
  14. #include <Files.h>
  15. #include <LowMem.h>
  16. #include <SCSI.h>  // For Block 0 and some partition map definitions.
  17.  
  18. #include "UnitTableFunctions.h"
  19. #include "UnitTableFloppySupport.h"
  20. #include "UnitTableDriveQSupport.h"
  21. #include "UnitTableDeviceAccess.h"
  22. #include "UnitTableDriverIcons.h"
  23. #include "UnitTableReadWriteSupport.h"
  24.  
  25. // pmPartStatus field flags
  26. // Old versions from ATA and SCSI - should be deprecated
  27. // but need to be supported since they are used by Drive Setup.
  28. enum 
  29. {
  30.     kPMapDriveSetupSig    =    'DSU1',
  31.     STAT_WRITABLE        =    0x20,
  32.     STAT_MOUNT            =    0x40000000,
  33.     STAT_STARTUP        =    0x80000000
  34. };
  35.  
  36. // New fields that will definitely be added to SCSI.h (should add the AUX fields also)
  37. enum
  38. {
  39.     // Drive Setup doesn't play nicely with others or these values
  40. /*    kPartitionHFSIsWriteProtected    = 0x00000100,*/
  41. /*    kPartitionHFSDoNotAutomount        = 0x00000200,*/
  42. /*    kPartitionHFSIsStartup            = 0x00000400,    // This may not be needed for new drivers*/
  43. /**/
  44. /*    kPartitionHFSStatusBitsMask        = 0x0000FF00*/
  45.     kPartitionHFSIsWriteProtected    = 0x00010000,
  46.     kPartitionHFSDoNotAutomount        = 0x00020000,
  47.     kPartitionHFSIsStartup            = 0x00040000,    // This may not be needed for new drivers
  48.  
  49.     kPartitionHFSStatusBitsMask        = 0x00FF0000
  50. };
  51.  
  52. enum
  53. {
  54.     kInstallStartState = 1,
  55.     kInstallPartitionReadDoneState,
  56.     kInstallReadNextPartBlock,
  57.     kInstallProcessNextPartBlock
  58. };
  59.  
  60. typedef struct InstallPB
  61. {
  62.     volatile OSStatus                status;
  63.     void                             *ourCompletion;
  64.     UInt32                            capacity;
  65.     UInt32                            blockSize;
  66.     OSType                            currentMediaType;
  67.     UInt8                            currentState;
  68.     UInt32                            currentPartBlock;
  69.     UInt32                            lastPartBlock;
  70.     DriveInstallCompletionProcPtr    installCompletion;
  71.     Boolean                            useNativeBlocks;
  72.     UInt8                            buffer[2048];
  73. };
  74.  
  75. typedef    struct InstallPB    InstallPB, *InstallPBPtr;
  76.  
  77. #define kNumberOfDriveRecords    12
  78.  
  79. static InstallPB    theInstallPB;
  80. static DriveQRec    theDriveQRecArray[kNumberOfDriveRecords];
  81. static DriverRefNum    gOurDrvrRefNum;
  82. static TimerID        gPostEventTimer = 0;
  83. static UInt16        gCurrentDriverMode = kDriverModeNormal;
  84. static Boolean        gDoPostEvents = true;
  85.  
  86. static void         ResetDriveQueue( DriveQRecPtr drive);
  87. static DriveQRecPtr FindPermanentDriveQRec( void );
  88.  
  89. static DriveQRecPtr    CreateDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset );
  90.  
  91. static void         ScanMediaForPartitions( UInt32 userData, OSStatus status );
  92.  
  93. static Boolean         ShouldPartitionBeMounted( Partition* thePartition );
  94.  
  95. static void             EjectDrive(DriveQRecPtr theDrivePtr);
  96. static OSStatus        PostTheDiskInsertEvents( void );
  97. static OSStatus     RetryPostEventInterrupt( void *p1, void *p2);
  98.  
  99. // This may be removed
  100. static Boolean         IsVolumeMountedForDrive(UInt16 driveNum);
  101.  
  102. #pragma mark --
  103. #pragma mark Driver Mode routines
  104. static UInt32 gModeUserData;
  105. static UInt16 ReadOnlyMediaDriveNum = 0;
  106. static ControlStatusCompletionProcPtr gModeCompletionProc;
  107.  
  108. static void StartNormalModeCompletion(Boolean wasSuccessful);
  109.  
  110. OSStatus DriveQueueControlCallSupport(     UInt32                                    userData,
  111.                                         CntrlParamPtr                            cntrlPBPtr,
  112.                                         ControlStatusCompletionProcPtr            callBack )
  113. {
  114.     OSStatus        err        = noErr;
  115.     SInt16            driveNum;
  116.  
  117.     gModeUserData             = userData;
  118.     gModeCompletionProc     = callBack;
  119.  
  120.     driveNum = cntrlPBPtr->ioVRefNum;
  121.     
  122.     // Parse the control codes…
  123.     switch( cntrlPBPtr->csCode ) 
  124.     {
  125.         case kcsSetDriverMode:                        // Change the driver's operating mode
  126.         {
  127.             UInt16             newMode = cntrlPBPtr->csParam[0];
  128.             DriveQRecPtr    driveQPtr;
  129.             Boolean         volumeMounted = false;
  130.                                 
  131.             if ( newMode == gCurrentDriverMode )
  132.             {
  133.                 // The new mode is the same as the current mode, do nothing
  134.                 // and return noErr
  135.                 err = noErr;
  136.                 break;
  137.             }
  138.             
  139.             driveQPtr = GetFirstDriveQRec();
  140.             while ( driveQPtr != nil )
  141.             {
  142.                 // Check each drive owned by the driver for mounted volumes
  143.                 if ( IsVolumeMountedForDrive ( driveQPtr->driveNum ) == true )
  144.                 {
  145.                     // There are still volumes mounted for the drive, this prevents
  146.                     // the driver from changing modes.
  147.                     volumeMounted = true;
  148.                     break;
  149.                 }
  150.                 
  151.                 driveQPtr = GetNextDriveQRec( driveQPtr );
  152.             }
  153.     
  154.             if (volumeMounted == true )
  155.             {
  156.                 err = paramErr;
  157.                 break;
  158.             }
  159.  
  160.             if ( newMode == kDriverModeNormal )
  161.             {
  162.                 gCurrentDriverMode = newMode;
  163.                 if ( cntrlPBPtr->csParam[1] != 0 )
  164.                 {
  165.                     gDoPostEvents = false;
  166.                 }
  167.                 
  168.                 EjectDrive( FindPermanentDriveQRec());
  169.                  InstallDrive( &StartNormalModeCompletion );
  170.                 err = kRequestPending;
  171.             }
  172.             else if ( newMode == kDriverModeUtility )
  173.             {
  174.                 // Set mode to utility
  175.                 gCurrentDriverMode = newMode;
  176.  
  177.                 // Do an eject on all drive Q elements to remove from the queue
  178.                 driveQPtr = GetFirstDriveQRec();
  179.                 while ( driveQPtr != nil )
  180.                 {
  181.                     if ( driveQPtr != FindPermanentDriveQRec())
  182.                     {
  183.                         EjectDrive( driveQPtr );
  184.                     }
  185.                     
  186.                     driveQPtr = GetNextDriveQRec( driveQPtr );
  187.                 }
  188.                 
  189.                 // Update the permanent to represent the entire media
  190.                 FindPermanentDriveQRec()->partoffset = FindPermanentDriveQRec()->curoffset = 0;
  191.                 UpdateQ(FindPermanentDriveQRec()->driveNum, FindPermanentDriveQRec()->capacity);
  192.                 err = noErr;
  193.             }
  194.             else
  195.             {
  196.                 err = paramErr;
  197.             }
  198.         }
  199.         break;
  200.  
  201.         case kcsManageReadOnlyMediaQueue:
  202.         {
  203.             UInt16             newMode = cntrlPBPtr->csParam[0];
  204.             DriveQRecPtr    driveQPtr;
  205.  
  206.             if ( newMode == kReadOnlyMediaQueueInstall )
  207.             {
  208.                 // Install a Write protected Drive queue element to represent the entire media
  209.                 // and return the DriveNum in csParam[1]
  210.                 if ( GetNumberOfVolumes() == 0 )
  211.                 {
  212.                     // There are no mounted volumes, and so probably no media in the\
  213.                     // drive.  Return a paramErr.
  214.                     err = paramErr;
  215.                     break;
  216.                 }
  217.                 
  218.                 driveQPtr = CreateNewDriveQRecForPartition( NextPartitionID(), 0, 0 );
  219.                 if ( driveQPtr ) 
  220.                 {
  221.                     driveQPtr->isWriteProtected = true;
  222.  
  223.                     UpdateQ(driveQPtr->driveNum, driveQPtr->capacity);
  224.                     ReadOnlyMediaDriveNum = cntrlPBPtr->csParam[1] = driveQPtr->driveNum;
  225.                     err = noErr;
  226.                 }
  227.                 else
  228.                 {
  229.                     err = controlErr;
  230.                 }
  231.             }
  232.             else if ( newMode == kReadOnlyMediaQueueRemove )
  233.             {
  234.                 // If there is a Read Only Media drive queue installed, remove it now
  235.                 
  236.                 // Make sure that the passed in drive does not have a mounted volume.
  237.                 if ( IsVolumeMountedForDrive ( ReadOnlyMediaDriveNum ) == true )
  238.                 {
  239.                     // There are still volumes mounted for the drive, this means that
  240.                     // this is not the Read Only queue.  Return paramErr.
  241.                     err = paramErr;
  242.                     break;
  243.                 }
  244.  
  245.                 driveQPtr = FindDriveQRecForDriveNum( ReadOnlyMediaDriveNum );
  246.                 if ( driveQPtr != nil )
  247.                 {
  248.                     RemoveDrive(driveQPtr);
  249.                     err = noErr;
  250.                 }
  251.                 else
  252.                 {
  253.                     err = paramErr;
  254.                 }
  255.                 
  256.                 ReadOnlyMediaDriveNum = 0;
  257.             }
  258.             else
  259.             {
  260.                 // The function passed in is not defined, return a paramErr.
  261.                 err = paramErr;
  262.             }
  263.         }
  264.         break;
  265.  
  266.         default:
  267.         {
  268.             err = controlErr;
  269.         }
  270.         break;
  271.     }
  272.     
  273.     return err;
  274. }
  275.  
  276. void StartNormalModeCompletion(Boolean wasSuccessful)
  277. {
  278.     OSStatus    err;
  279.     
  280.     gDoPostEvents = true;
  281.     if ( wasSuccessful == true )
  282.     {
  283.         err = noErr;
  284.     }
  285.     else
  286.     {
  287.         err = ioErr;
  288.     }
  289.  
  290.     (*gModeCompletionProc) (gModeUserData, err);
  291. }
  292.  
  293. OSStatus DriveQueueStatusCallSupport(     UInt32                            userData,
  294.                                         CntrlParamPtr                    cntrlPBPtr,
  295.                                         ControlStatusCompletionProcPtr    callBack )
  296. {
  297.     OSStatus        err    = noErr;
  298.     SInt16            driveNum;
  299.  
  300.     gModeUserData             = userData;
  301.     gModeCompletionProc     = callBack;
  302.  
  303.     driveNum = cntrlPBPtr->ioVRefNum;
  304.     
  305.     // Parse the control codes…
  306.     switch(cntrlPBPtr->csCode) 
  307.     {
  308.         case kcsGetDriverMode:
  309.         {
  310.             cntrlPBPtr->csParam[0] = gCurrentDriverMode;
  311.             if ( gCurrentDriverMode == kDriverModeUtility )
  312.             {
  313.                 // This is the get mode info call for Utility mode,
  314.                 // return the drive number representing the whole disk.
  315.                 cntrlPBPtr->csParam[1] = FindPermanentDriveQRec()->driveNum;
  316.             }
  317.             
  318.             err = noErr;
  319.         }
  320.         break;
  321.  
  322.         case kcsManageReadOnlyMediaQueue:
  323.         {
  324.             if ( ReadOnlyMediaDriveNum == 0 )
  325.             {
  326.                 err = paramErr;
  327.                 break;
  328.             }
  329.             
  330.             cntrlPBPtr->csParam[0] = ReadOnlyMediaDriveNum;            
  331.             err = noErr;
  332.         }
  333.         break;
  334.  
  335.         default:
  336.         {
  337.             err = statusErr;
  338.         }
  339.         break;
  340.     }
  341.     
  342.     return err;
  343. }
  344.  
  345.  
  346. #pragma mark --
  347. #pragma mark Drive Information Query Functions
  348. Boolean IsDriveNumberValid( UInt16 driveNum )
  349. {
  350.     DriveQRecPtr theDriveQRec;
  351.  
  352.     theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  353.     if ( theDriveQRec != nil )
  354.     {
  355.         return true;
  356.     }
  357.     
  358.     return false;
  359. }
  360.  
  361. Boolean IsDriveNumWriteProtected( UInt16 driveNum )
  362. {
  363.     DriveQRecPtr theDriveQRec;
  364.  
  365.     if( IsDriveAFloppy( driveNum ) == true )
  366.     {
  367.         theDriveQRec = GetFloppyDriveRec();
  368.     }
  369.     else
  370.     {
  371.         theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  372.     }
  373.     
  374.     if ( theDriveQRec != nil )
  375.     {
  376.         return theDriveQRec->isWriteProtected;
  377.     }
  378.     
  379.     return false;
  380. }
  381.  
  382. Boolean AreThereMountedDrives( void )
  383. {
  384.     int    loopCount;
  385.     
  386.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  387.     {
  388.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  389.         {
  390.             return true;
  391.         }
  392.     }
  393.     
  394.     return false;
  395. }
  396.  
  397. UInt32 GetNumberOfVolumes( void )
  398. {
  399.     int        loopCount;
  400.     UInt32    volCount = 0;
  401.     
  402.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  403.     {
  404.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  405.         {
  406.             volCount++;
  407.         }
  408.     }
  409.     
  410.     return volCount;
  411. }
  412.  
  413. OSType GetMediaTypeForDriveNum( UInt16 driveNum )
  414. {
  415.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  416.     
  417.     drive = FindDriveQRecForDriveNum( driveNum );
  418.     return drive->deviceType;
  419. }
  420.  
  421. void GetMediaIconForDriveNum( UInt16 driveNum, DiskIcon    *iconPtr )
  422. {
  423.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  424.     
  425.     drive = FindDriveQRecForDriveNum( driveNum );
  426.     BlockMove(drive->mediaIconPtr, iconPtr, sizeof(DiskIcon));
  427. }
  428.  
  429. void GetDriveStatusForDriveNum( UInt16 driveNum, DrvSts *statusPtr )
  430. {
  431.     DriveQRecPtr    drive = nil;        // pointer to our volume record structure
  432.     
  433.     drive = FindDriveQRecForDriveNum( driveNum );
  434.     BlockMove(&drive->driveStatus, statusPtr, sizeof(DrvSts));
  435. }
  436.  
  437. #pragma mark --
  438. #pragma mark Drive Queue Management Functions
  439. // This is to workaround a bug in the PowerPC native version of the AddDrive
  440. // call in systems before 8.5, where one needs to be added to the desired
  441. // drive number before calling AddDrive.
  442. void NativeAddDrive(DriverRefNum drvrRefNum, UInt16 driveNumber, DrvQElPtr drvQEl)
  443. {
  444.     UInt32        gestaltResponse;
  445.     OSStatus    gestaltErr;
  446.  
  447.     // Check System version to see if we need to add one to AddDrive calls
  448.     gestaltErr = Gestalt(gestaltSystemVersion,(long *) &gestaltResponse);
  449.  
  450.     // If this is boot time, the system version will be reported as 0x0000.  
  451.     // If we are booting, we must be on a system greater than 8.5, so we do not need the fix
  452.     if( (gestaltErr == noErr) && (( (gestaltResponse&0xFFFF) < 0x0850 ) && ((gestaltResponse&0xFFFF) != 0x0000 )))
  453.     {
  454.         // We are on a system before 8.5, we need to add 1 to AddDrive calls
  455.         driveNumber += 1;
  456.     }
  457.  
  458.     AddDrive( drvrRefNum, driveNumber, drvQEl);
  459. }
  460.  
  461. void ResetDriveQueue( DriveQRecPtr drive)
  462. {
  463.     if(drive->isFloppy == true)
  464.     {
  465.         ResetFloppyDriveQueue( drive );
  466.     }
  467.     else
  468.     {
  469.         drive->driveStatus.track         = 0;            // Not used on non floppies
  470.         drive->driveStatus.writeProt     = 0;            // not write protected yet
  471.         drive->driveStatus.diskInPlace     = 0;            // Ejectable Disk
  472.         drive->driveStatus.installed     = 1;            // drive is installed
  473.         drive->driveStatus.sides         = 0;            // Not used on non floppy disks
  474.         drive->driveStatus.qType         = 1;            // both dQDrvSz and dQDrvSz2 are used
  475.         drive->driveStatus.dQFSID         = 0;            // File Manager's volume type
  476.         drive->driveStatus.driveSize    = 0;            // volume size in blocks
  477.         drive->driveStatus.driveS1         = 0;
  478.     }
  479. }
  480.  
  481. static Boolean    driveQueueIsInstalled = false;
  482.  
  483. OSStatus InstallDriveQueueElement( DriverRefNum theDrvrRefNum )
  484. {
  485.     OSStatus                                     err = noErr;
  486.     int                                            loopCount;
  487.     DriveQRecPtr                                theDriveQPtr = nil;
  488.     DriverGestaltSupportedMediaTypesResponse    *supportedTypes;
  489.     
  490.     gOurDrvrRefNum = theDrvrRefNum;
  491.     
  492.     if(IsDeviceAccessEnabled() == false )
  493.     {
  494.         return kDeviceAccessNotAvailable;
  495.     }
  496.  
  497.     if ( driveQueueIsInstalled == true )
  498.     {
  499.         return noErr;
  500.     }
  501.  
  502.     driveQueueIsInstalled = true;
  503.  
  504.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  505.     {
  506.         BlockZero( &theDriveQRecArray[loopCount], sizeof( DriveQRec ));
  507.         theDriveQRecArray[loopCount].isValidRecord = false;
  508.     }
  509.     
  510.     supportedTypes = GetSupportedMediaTypesPtr();
  511.     
  512.     for ( loopCount = 0; loopCount < supportedTypes->supportTypesCount; loopCount++)
  513.     {
  514.         if ( supportedTypes->supportedTypesArray[loopCount] == kdgFloppyType )
  515.         {
  516.             err = SetupFloppyStructures( theDrvrRefNum );
  517.         }
  518.         else
  519.         {
  520.             theDriveQPtr = GetNewDriveQRec();
  521.             ResetDriveQueue( theDriveQPtr );
  522.             theDriveQPtr->deviceType = supportedTypes->supportedTypesArray[loopCount];
  523.             theDriveQPtr->driveNum = NextQDrive();                    // assign a logical drive number
  524.             theDriveQPtr->isPermanentQElement = true;
  525.             NativeAddDrive(theDrvrRefNum, theDriveQPtr->driveNum,(DrvQElPtr)  &theDriveQPtr->driveStatus.qLink);
  526.         }
  527.     }
  528.     
  529.     if ( theDriveQPtr != nil )
  530.     {
  531.         // Wait until after the floppy queue is added to clear this field
  532.         // This prevents floppy from getting the same drive queue element on devices
  533.         // that support both floppy and non-floppy removables
  534.         theDriveQPtr->isValidRecord = false;
  535.     }
  536.  
  537.     return err;
  538. }
  539.  
  540. OSStatus RemoveDriveQueueElement( void )
  541. {
  542.     DriveQRecPtr    theDriveQRec;
  543.  
  544.     if( gPostEventTimer != nil )
  545.     {
  546.         AbsoluteTime    timeLeft;
  547.         
  548.         // Cancel any pending timers, we don't care what the
  549.         // returned status is.
  550.         (void) CancelTimer( gPostEventTimer, &timeLeft);
  551.         gPostEventTimer = 0;
  552.     }
  553.     
  554.     driveQueueIsInstalled = false;
  555.  
  556.     theDriveQRec = GetFirstDriveQRec();                        // first volume of the drive
  557.     while (theDriveQRec)
  558.     {
  559.         EjectDrive( theDriveQRec );
  560.         theDriveQRec = GetNextDriveQRec( theDriveQRec );    // point to the next volume
  561.     }
  562.  
  563.     // if we installed a fixed/removable drive queue, remove it.
  564.     theDriveQRec = FindPermanentDriveQRec();
  565.     
  566.     if ( theDriveQRec != nil )
  567.     {
  568.         RemoveDrive( theDriveQRec );
  569.     }
  570.     
  571.     RemoveFloppyStructures();
  572.     
  573.     return noErr;
  574. }
  575.  
  576. void EjectDriveNum( UInt16 driveNum )
  577. {
  578.     DriveQRecPtr theDriveQRec;
  579.     
  580.     theDriveQRec = FindDriveQRecForDriveNum( driveNum );
  581.     if ( theDriveQRec != nil )
  582.     {
  583.         EjectDrive( theDriveQRec );
  584.     }
  585. }
  586.  
  587. // DriveQRec management functions
  588. DriveQRecPtr    GetNewDriveQRec( void )
  589. {
  590.     int                loopCount;
  591.     DriveQRecPtr    permRec;
  592.     
  593.     permRec = FindPermanentDriveQRec();
  594.     
  595.     if ( permRec != nil )
  596.     {
  597.         if ( permRec->isValidRecord == false )
  598.         {
  599.             permRec->isValidRecord = true;
  600.             return permRec;
  601.         }
  602.     }
  603.  
  604.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  605.     {
  606.         if (( theDriveQRecArray[loopCount].isValidRecord == false ) && ( theDriveQRecArray[loopCount].isFloppy == false ))
  607.         {
  608.             theDriveQRecArray[loopCount].isValidRecord = true;
  609.             return &theDriveQRecArray[loopCount];
  610.         }
  611.     }
  612.     
  613.     return nil;
  614. }
  615.  
  616. void FreeDriveQRec( DriveQRecPtr theDriveRecPtr )
  617. {
  618.     if ( theDriveRecPtr!=nil )
  619.     {
  620.         if ( theDriveRecPtr->isFloppy == true )
  621.         {
  622.             ResetFloppyDriveQueue(theDriveRecPtr);    
  623.             theDriveRecPtr->isValidRecord = false;
  624.         }
  625.         else if ( theDriveRecPtr->isPermanentQElement == true )
  626.         {
  627.             ResetDriveQueue(theDriveRecPtr);    
  628.             theDriveRecPtr->isValidRecord = false;
  629.         }
  630.         else
  631.         {
  632.             BlockZero( theDriveRecPtr, sizeof( DriveQRec ));
  633.             theDriveRecPtr->isValidRecord = false; // this is actually done by blockZero, repeated for emphasis
  634.         }
  635.     }
  636. }
  637.  
  638. DriveQRecPtr FindDriveQRecForDriveNum( UInt16 driveNum )
  639. {
  640.     int    loopCount;
  641.     
  642.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  643.     {
  644.         if (( theDriveQRecArray[loopCount].driveNum == driveNum ) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  645.         {
  646.             return &theDriveQRecArray[loopCount];
  647.         }
  648.         
  649.         if (( theDriveQRecArray[loopCount].driveNum == driveNum ) && ( theDriveQRecArray[loopCount].isPermanentQElement == true ))
  650.         {
  651.             return &theDriveQRecArray[loopCount];
  652.         }
  653.     }
  654.     
  655.     return nil;
  656. }
  657.  
  658. DriveQRecPtr FindDriveQRecForPartitionNum( UInt32 partNum )
  659. {
  660.     int    loopCount;
  661.     
  662.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  663.     {
  664.         if (( theDriveQRecArray[loopCount].partitionNo == partNum ) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  665.         {
  666.             return &theDriveQRecArray[loopCount];
  667.         }
  668.     }
  669.     
  670.     return nil;
  671. }
  672.  
  673. DriveQRecPtr FindPermanentDriveQRec( void )
  674. {
  675.     int    loopCount;
  676.     
  677.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  678.     {
  679.         if (( theDriveQRecArray[loopCount].isPermanentQElement == true ) && ( theDriveQRecArray[loopCount].isFloppy == false ))
  680.         {
  681.             return &theDriveQRecArray[loopCount];
  682.         }
  683.     }
  684.     
  685.     return nil;
  686. }
  687.  
  688. DriveQRecPtr GetFirstDriveQRec( void )
  689. {
  690.     int    loopCount;
  691.     
  692.     for ( loopCount = 0; loopCount < kNumberOfDriveRecords; loopCount++)
  693.     {
  694.         if ( theDriveQRecArray[loopCount].isValidRecord == true )
  695.         {
  696.             return &theDriveQRecArray[loopCount];
  697.         }
  698.     }
  699.  
  700.     return nil;
  701. }
  702.  
  703. DriveQRecPtr GetNextDriveQRec( DriveQRecPtr theDriveQRec )
  704. {
  705.     int    loopCount;
  706.     int    inDriveQNum;
  707.     
  708.     for ( inDriveQNum = 0; inDriveQNum < kNumberOfDriveRecords; inDriveQNum++)
  709.     {
  710.         if ( &theDriveQRecArray[inDriveQNum] == theDriveQRec )
  711.         {
  712.             break;
  713.         }
  714.     }
  715.  
  716.     if ( inDriveQNum < kNumberOfDriveRecords )
  717.     {
  718.         for ( loopCount = inDriveQNum; loopCount < kNumberOfDriveRecords; loopCount++)
  719.         {
  720.             if ((loopCount != inDriveQNum) && ( theDriveQRecArray[loopCount].isValidRecord == true ))
  721.             {
  722.                 return &theDriveQRecArray[loopCount];
  723.             }
  724.         }
  725.     }
  726.  
  727.     return nil;
  728. }
  729.  
  730. //------------------------------------------------------------------------------
  731. //    Function:        CreateDriveQRecForPartition
  732. //
  733. //    Description:    This function creates a volume record for the specified drive.
  734. //                        The volume is appended to the drive's volume queue and a logical
  735. //                        logical drive is installed in the system drive queue.
  736. //                    
  737. //    Input:            drive:            pointer to the drive record of the volume to create
  738. //                    partitionID:    the volume's partition ID
  739. //                    volSize:        size of the volume in blocks
  740. //                    volOffset:        block offset of volume on drive
  741. //
  742. //    Output:            Returns nil pointer if fails, else pointer to volume record
  743. //
  744. //    NOTE:            Assumes all inputs are valid!
  745. //-------------------------------------------------------------------------------
  746. DriveQRecPtr CreateDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset )
  747. {
  748.     DriveQRecPtr        driveRec;
  749.     UInt32                currentCapacity, currentBlockSize;
  750.     Boolean                isWriteProtected;
  751.     OSType                currentType;     
  752.     
  753.     GetMediaProperties( ¤tCapacity,  ¤tBlockSize, &isWriteProtected, ¤tType); 
  754.     
  755.     if ( currentType == kdgFloppyType )
  756.     {
  757.         driveRec = GetFloppyDriveRec();
  758.     }
  759.     else
  760.     {
  761.         // Search for a DriveQRec record for the partition to be created…
  762.         driveRec = FindDriveQRecForPartitionNum( partitionID );
  763.     }
  764.     
  765.     if ( driveRec != nil )                                            // if record exists for this partition…
  766.     {
  767.         if (driveRec->driveStatus.diskInPlace)                        // if partition is already online…
  768.         {                                                            // we shouldn't be here - fall thru
  769.             return nil;
  770.         }
  771.     }
  772.     else                                                            // need to create DriveQRec
  773.     {
  774.         driveRec = GetNewDriveQRec();                                // Allocate storage for record
  775.     }
  776.     
  777.     if (driveRec)                                                    // If a DriveQRec was created.
  778.     {
  779.  
  780.         driveRec->isValidRecord = true;
  781.  
  782.         driveRec->isWriteProtected = isWriteProtected;
  783.         
  784.         if( driveRec->isWriteProtected == true)
  785.         {
  786.             driveRec->driveStatus.writeProt     = 0x80;                // disk is write protected
  787.         }
  788.         else
  789.         {
  790.             driveRec->driveStatus.writeProt     = 0;                // not write protected yet
  791.         }
  792.  
  793.         if ( currentType == kdgDiskType )
  794.         {
  795.             // This disk is non-ejectable
  796.             driveRec->driveStatus.diskInPlace     = 0x48;                // Non-Ejectable Disk, but we want eject calls
  797.         }
  798.         else
  799.         {
  800.             // This is a removable disk
  801.             driveRec->driveStatus.diskInPlace     = 1;                // Ejectable Disk
  802.         }
  803.  
  804.         driveRec->driveStatus.installed     = 1;                    // drive is installed
  805.         driveRec->driveStatus.dQFSID         = 0;                    // File Manager's volume type
  806.  
  807.         if( driveRec->isFloppy == false)
  808.         {
  809.             driveRec->driveStatus.qType         = 1;                            // both dQDrvSz and dQDrvSz2 are used
  810.             driveRec->driveStatus.driveSize        = (UInt16) partitionSize;        // partition size in blocks
  811.             driveRec->driveStatus.driveS1         = (UInt16) (partitionSize >> 16);
  812.         }
  813.  
  814.         driveRec->mountPartition =        false;                                // don't mount this volume,
  815.         driveRec->diskInsertPosted =    false;                                // it's not mounted yet,
  816.         driveRec->partitionNo =            partitionID;                        // save the partition ID
  817.  
  818.         // Save volume's block offset and set its access mode by setting curoffset to the
  819.         // same (access is relative to partition offset if curoffset is non-zero, else physical)
  820.         driveRec->curoffset     = partitionOffset;                        // block offset of partition
  821.         driveRec->partoffset     = partitionOffset;                        // partition offset
  822.         driveRec->partblks         = partitionSize;                        // save size for our use also
  823.         driveRec->blockSize     = currentBlockSize;
  824.         if ( currentBlockSize == kFileSystemRequestBlockSize )
  825.         {
  826.             // Blocksize is the same as the file system default
  827.             driveRec->capacity         = currentCapacity;
  828.         }
  829.         else
  830.         {
  831.             // Blocksize is not the same as the file system default,
  832.             // modify the capcity to reflect the number of file system blocks
  833.             driveRec->capacity         = currentCapacity * ( currentBlockSize / kFileSystemRequestBlockSize );
  834.         }
  835.  
  836.         // Save the media type in the DriveQRec
  837.         driveRec->deviceType = currentType;
  838.  
  839.         driveRec->mediaIconPtr = (Ptr) GetOneBitIconPtr( driveRec->deviceType );
  840.     }
  841.     
  842.     return(driveRec);
  843. }
  844.  
  845.  
  846. //------------------------------------------------------------------------------
  847. //    Function:        ScanMediaForPartitions
  848. //    Description:    Searches for partitions on the media and installs them as
  849. //                    volumes for the associated drive.  Assumes the drive does
  850. //                    not have any volumes installed yet. 
  851. //
  852. //    Input:            theDrive:    pointer to drive record
  853. //                    mountVols:    true means to mount the drive's partitions
  854. //
  855. //-------------------------------------------------------------------------------
  856. void ScanMediaForPartitions( UInt32 userData, OSStatus status )
  857. {
  858.     Boolean            timetoMountThePartitions = false;
  859.     InstallPBPtr     installPBPtr;
  860.     Boolean         weHaveAFloppy = false;
  861.     
  862.     installPBPtr = (InstallPBPtr) userData;
  863.     installPBPtr->status = status;
  864.     
  865.     switch(installPBPtr->currentState)
  866.     {
  867.         case kInstallStartState:
  868.         {
  869.             if ( theInstallPB.currentMediaType == kdgFloppyType )
  870.             {
  871.                 // If we have a floppy disk, no need to scan for partitions
  872.                 // go ahead and mount the whole disk as a volume.
  873.                 // This also allows for unformatted media to be formatted.
  874.                 weHaveAFloppy = true;
  875.                 timetoMountThePartitions = true;
  876.                 break;
  877.             }
  878.  
  879.             installPBPtr->currentState = kInstallPartitionReadDoneState;
  880.             
  881.             // Read block 0
  882.             installPBPtr->status = DoReadWritePhysicalBlocks (    (UInt32) installPBPtr, 0, 1, installPBPtr->blockSize, true,
  883.                                                             (Ptr) installPBPtr->buffer, (kFileSystemRequestBlockSize), false, &ScanMediaForPartitions );
  884.         }
  885.         break;
  886.         
  887.         case kInstallPartitionReadDoneState:
  888.         {
  889.             UInt8            *buf = (UInt8 *) &installPBPtr->buffer;            // Share 512 byte storage with PMap
  890.             Boolean            checkMacPartitions = true;
  891.             
  892.             if (installPBPtr->status == noErr)
  893.             {
  894.                 Block0        *blkZero;
  895.                 
  896.                 blkZero = (Block0 *) buf;
  897.                 
  898.                 // Check for Macintosh partitions if Block0 has the correct signature.
  899.                 checkMacPartitions = ( blkZero->sbSig == sbSIGWord );
  900.                 
  901.                 // -----  PC-Exchange DOS format bug fix  ------
  902.                 // PCX does not erase the partition map (blocks 1-31) when reformatting HFS to 
  903.                 // DOS so we may still find a partition map.  Check for DOS signature in block 0,
  904.                 // and if there, the Macintosh partition map is invalid. 
  905.                 // check for Macintosh partitions if not a DOS signature
  906. /*                checkMacPartitions = !(buf[kDOSSigLow] == kDOSSigValLo && buf[kDOSSigHi] == kDOSSigValHi);*/
  907.             }
  908.             else
  909.             {
  910.                 // An error occurred on the read, return back a failure to the client
  911.                 installPBPtr->status = ioErr;
  912.                 break;
  913.             }
  914.             
  915.             if (checkMacPartitions == false)                // we don't need to check for Macintosh parititions…
  916.             {
  917.                 timetoMountThePartitions = true;            // we found a DOS signature, try to mount as DOS
  918.                 break;
  919.             }
  920.             
  921.             installPBPtr->lastPartBlock = 1;                // assume no partition map will be found
  922.             installPBPtr->currentPartBlock = 1;
  923.  
  924.         }                                                    // no break, we want to execute next case
  925.         
  926.         case kInstallReadNextPartBlock:
  927.         {            
  928.             if ( installPBPtr->currentPartBlock <= installPBPtr->lastPartBlock )
  929.             {
  930.                 UInt32        blockSizeForRead;
  931.                 Boolean        convertToSystemBlocks;
  932.                 
  933.                 if ( installPBPtr->useNativeBlocks == true )
  934.                 {
  935.                     blockSizeForRead = installPBPtr->blockSize;
  936.                     convertToSystemBlocks = false;
  937.                 }
  938.                 else
  939.                 {
  940.                     blockSizeForRead = kFileSystemRequestBlockSize;
  941.                     convertToSystemBlocks = true;
  942.                 }
  943.                 
  944.                 // Read a block from the media…
  945.                 installPBPtr->currentState = kInstallProcessNextPartBlock;
  946.                 installPBPtr->status = DoReadWritePhysicalBlocks (    (UInt32) installPBPtr, installPBPtr->currentPartBlock, 1, installPBPtr->blockSize, convertToSystemBlocks,
  947.                                             (Ptr) installPBPtr->buffer, blockSizeForRead, false, &ScanMediaForPartitions );
  948.             }
  949.             else
  950.             {
  951.                 timetoMountThePartitions = true;            // we have finished scanning the partition map, mount what we have found
  952.             }
  953.         }
  954.         break;
  955.         
  956.         case kInstallProcessNextPartBlock:
  957.         {
  958.             Partition    *PartMap = (Partition *) &installPBPtr->buffer;
  959.             Boolean        mountPartition;
  960.             
  961.             if ( installPBPtr->status != noErr )
  962.             {
  963.                 installPBPtr->currentPartBlock += 1;
  964.                 installPBPtr->currentState = kInstallReadNextPartBlock;
  965.                 ScanMediaForPartitions( (UInt32) installPBPtr, noErr );
  966.                 return;
  967.             }
  968.     
  969.             // Verify we read a partition map entry…
  970.             if (PartMap->pmSig != newPMSigWord)         // Partition map signature?
  971.             {
  972.                 if (( installPBPtr->currentPartBlock == 1 ) && ( installPBPtr->blockSize != kFileSystemRequestBlockSize ))
  973.                 {
  974.                     // If there is not a valid Partition Map signature and the
  975.                     // drive has blocks other than the standard 512 byte blocks,
  976.                     // the partition map may be written on native blocks.
  977.                     installPBPtr->useNativeBlocks = true;
  978.                 }
  979.                 else
  980.                 {
  981.                     installPBPtr->currentPartBlock += 1;
  982.                 }
  983.                 
  984.                 installPBPtr->currentState = kInstallReadNextPartBlock;
  985.                 ScanMediaForPartitions( (UInt32) installPBPtr, noErr );
  986.                 return;
  987.             }
  988.     
  989.             if (installPBPtr->lastPartBlock == 1)                         // Readjust the number of map blocks
  990.                 installPBPtr->lastPartBlock = PartMap->pmMapBlkCnt;
  991.     
  992.             // Determine the partition type and do what is needed…
  993.             mountPartition = ShouldPartitionBeMounted( PartMap );
  994.             if ( mountPartition == true )
  995.             {
  996.                 DriveQRecPtr    newDriveRec;
  997.                 UInt32            blockCnt;
  998.                 UInt8            blockMultiplier = 1;
  999.                 
  1000.                 // LaCie hard drive fix                    
  1001.                 if ( PartMap->pmDataCnt == 0)
  1002.                 {
  1003.                     blockCnt = PartMap->pmPartBlkCnt;
  1004.                 }
  1005.                 else
  1006.                 {
  1007.                     blockCnt = PartMap->pmDataCnt;
  1008.                 }
  1009.                 
  1010.                 if ( installPBPtr->useNativeBlocks == true )
  1011.                 {
  1012.                     blockMultiplier = (installPBPtr->blockSize)/kFileSystemRequestBlockSize;
  1013.                 }
  1014.  
  1015.                 // A valid paritition found!  Create a DriveQRec for it.
  1016.                 newDriveRec = CreateDriveQRecForPartition( installPBPtr->currentPartBlock * blockMultiplier, blockCnt * blockMultiplier,
  1017.                                     ( PartMap->pmPyPartStart * blockMultiplier) + ( PartMap->pmLgDataStart * blockMultiplier) );
  1018.  
  1019.                 if ( newDriveRec == nil )                // If we failed, try the next partition
  1020.                 {
  1021.                     break;
  1022.                 }
  1023.  
  1024.                 // Save this partition's map entry number (remember to subtract 1 since the partition map starts on block 1)
  1025.                 newDriveRec->partMapEntryNum = installPBPtr->currentPartBlock-1;
  1026.             
  1027.                 // Determine if the old or new bits should be used
  1028.                 if ( *((UInt32 *) &PartMap->pmPad[0x50]) == kPMapDriveSetupSig )
  1029.                 {
  1030.                     // This Partition Map has the DriveSetup signature, check the old bits
  1031.                     // Check if the partition is software write protected.  
  1032.                     if ((PartMap->pmPartStatus & STAT_WRITABLE) == STAT_WRITABLE)
  1033.                     {
  1034.                         // Only change the value in the drive queue element if it is write protected since if the media 
  1035.                         // is hardware write protected, the locked flag in the drive queue element will already reflect this.                
  1036.                         newDriveRec->writeProtectedPart     = false;
  1037.                     }
  1038.                     else
  1039.                     {
  1040.                         // This partition is not marked as writeable so the locked flag in the 
  1041.                         // drive queue needs to be set so that the OS won't try to write.
  1042.                         newDriveRec->writeProtectedPart     = true;
  1043.                         newDriveRec->driveStatus.writeProt     = 0x80;
  1044.                     }
  1045.     
  1046.                     if (( PartMap->pmPartStatus & STAT_MOUNT ) == STAT_MOUNT)
  1047.                     {    
  1048.                         // This partition should be mounted, set the flag so we will post a disk insert event
  1049.                         newDriveRec->mountPartition = true;
  1050.                     }
  1051.                     else
  1052.                     {
  1053.                         // Since we do not support the Drive Setup call to mount partitions,
  1054.                         // for now, we will just remove the DriveQRec from the list.
  1055.                         FreeDriveQRec( newDriveRec );
  1056.                     }
  1057.                 }
  1058.                 else
  1059.                 {
  1060.                     // Check if the partition is software write protected.  
  1061.                     if ((PartMap->pmPartStatus & kPartitionHFSIsWriteProtected) == kPartitionHFSIsWriteProtected)
  1062.                     {
  1063.                         // This partition is not marked as writeable so the locked flag in the 
  1064.                         // drive queue needs to be set so that the OS won't try to write.
  1065.                         newDriveRec->writeProtectedPart     = true;
  1066.                         newDriveRec->driveStatus.writeProt     = 0x80;
  1067.                     }
  1068.                     else
  1069.                     {
  1070.                         // Only change the value in the drive queue element if it is write protected since if the media 
  1071.                         // is hardware write protected, the locked flag in the drive queue element will already reflect this.                
  1072.                         newDriveRec->writeProtectedPart     = false;
  1073.                     }
  1074.     
  1075.                     if (( PartMap->pmPartStatus & kPartitionHFSDoNotAutomount ) != kPartitionHFSDoNotAutomount)
  1076.                     {    
  1077.                         // This partition should be mounted, set the flag so we will post a disk insert event
  1078.                         newDriveRec->mountPartition = true;
  1079.                     }
  1080.                     else
  1081.                     {
  1082.                         // Since we do not support the Drive Setup call to mount partitions,
  1083.                         // for now, we will just remove the DriveQRec from the list.
  1084.                         FreeDriveQRec( newDriveRec );
  1085.                     }
  1086.                 }
  1087.  
  1088. /*                if ((PartMap->pmPartStatus & kPartitionHFSIsStartup) == kPartitionHFSIsStartup)        // is this flagged as the boot partition?*/
  1089. /*                {*/
  1090. /*                    newDriveRec->startupPartition = true;*/
  1091. /*                }*/
  1092. /*                else*/
  1093. /*                {*/
  1094. /*                    newDriveRec->startupPartition = false;*/
  1095. /*                }*/
  1096.             }
  1097.  
  1098.             // Go to next Partition        
  1099.             installPBPtr->currentPartBlock += 1;
  1100.             installPBPtr->currentState = kInstallReadNextPartBlock;
  1101.             
  1102.             ScanMediaForPartitions( (UInt32) installPBPtr, installPBPtr->status );
  1103.             return;
  1104.         }
  1105.         break;
  1106.     }
  1107.  
  1108.     if ( timetoMountThePartitions == true )
  1109.     {
  1110.         DriveQRecPtr    theDriveQRec;
  1111.         
  1112.         // If no partitions were found from the search above we assume the following:
  1113.         //      1. A Macintosh partition map exists, but it has either no file system partitions
  1114.         //        or no partitions which we recognize (either or which is unlikely).
  1115.         //     2.    The media has a Macintosh floppy format (HFS with no partition map)
  1116.         //     3.    The media has a foreign format (DOS, etc.).
  1117.         //
  1118.         // In all cases we create a volume of the entire media capacity, post a disk inserted
  1119.         // event and let the File System Manager try and figure it out.  Note we post a disk
  1120.         // inserted event rather than notifying FSM so if the media is not recognized (because
  1121.         // it's unformatted or the correct file system is not installed) the system will prompt
  1122.         // with a "This is not a Macintosh disk…" message.  If we call FSM instead, the user will
  1123.         // not be prompted when the media is unformatted.  This provides a way to format media
  1124.         // and also allows us to eject PCMCIA drives which have no volumes (no icons on desktop).
  1125.                 
  1126.         if ( GetNumberOfVolumes() == 0)            // if no partitions were found…
  1127.         {
  1128.             // Create a volume of entire media capacity with partitionID of 1
  1129.             if ( installPBPtr->blockSize == kFileSystemRequestBlockSize)
  1130.             {
  1131.                 theDriveQRec = CreateDriveQRecForPartition( 1, installPBPtr->capacity, 0 );
  1132.             }
  1133.             else
  1134.             {
  1135.                 UInt32     FSBlocksPerDeviceBlocks;
  1136.                 
  1137.                 FSBlocksPerDeviceBlocks = installPBPtr->blockSize/kFileSystemRequestBlockSize;
  1138.                 
  1139.                 theDriveQRec = CreateDriveQRecForPartition( 1, (installPBPtr->capacity * FSBlocksPerDeviceBlocks), 0 );
  1140.             }
  1141.  
  1142.             if(theDriveQRec)
  1143.             {
  1144.                 theDriveQRec->mountPartition = true;                    // post disk inserted event later
  1145.             }
  1146.         }
  1147.  
  1148.         // DriveQRecs have been created for all partitions, now install them into the Drive Queue and 
  1149.         // let them system know about them by posting Disk Insert events.
  1150.         if ( weHaveAFloppy == true )
  1151.         {
  1152.             if    (theDriveQRec->mountPartition == true)            // Do not do Add Drive for partitions not to be mounted
  1153.             {
  1154.                 theDriveQRec->inDriveQ = true;                    // mark this entry as having been added to the drive Q.
  1155.             }
  1156.         }
  1157.         else
  1158.         {
  1159.             // Add the remaining volumes to the drive queue…
  1160.             theDriveQRec = GetFirstDriveQRec();            // first DriveQRec
  1161.             while (theDriveQRec)
  1162.             {
  1163.                 if    (theDriveQRec->mountPartition == true)        // Do not do Add Drive for partitions not to be mounted
  1164.                 {
  1165.                     if (theDriveQRec == FindPermanentDriveQRec())
  1166.                     {
  1167.                         //theDriveQRec->driveNum = (FindPermanentDriveQRec())->driveNum;    // assign a logical drive number
  1168.                     }
  1169.                     else
  1170.                     {
  1171.                         theDriveQRec->driveNum = NextQDrive();        // assign a logical drive number
  1172.                         NativeAddDrive(gOurDrvrRefNum, theDriveQRec->driveNum, (DrvQElPtr) &theDriveQRec->driveStatus.qLink);
  1173.                     }
  1174.                     
  1175.                     theDriveQRec->inDriveQ = true;                    // mark this entry as having been added to the drive Q.
  1176.                 }
  1177.                 
  1178.                 theDriveQRec = GetNextDriveQRec( theDriveQRec );                // point to the next volume
  1179.             }
  1180.         }
  1181.  
  1182.         if ( GetNumberOfVolumes() != 0 )
  1183.         {
  1184.             OSErr theErr;
  1185.  
  1186.             theErr = PostTheDiskInsertEvents();
  1187.             if(theErr != noErr)
  1188.             {
  1189.                 // For some reason, the disk could not be mounted,
  1190.                 // We should eject and let the user decide whether to try again.
  1191.                 (*installPBPtr->installCompletion)( false );
  1192.                 return;
  1193.             }
  1194.         }
  1195.         else                                                    // Abort if no volumes installed for drive        
  1196.         {
  1197.             (*installPBPtr->installCompletion)( false );
  1198.             return;
  1199.         }
  1200.     
  1201.         (*installPBPtr->installCompletion)( true );
  1202.         return;
  1203.     }
  1204.     
  1205.     if ((installPBPtr->status != 1 ) && (installPBPtr->status != noErr))
  1206.     {
  1207.         (*installPBPtr->installCompletion)( false );
  1208.     }
  1209. }
  1210.  
  1211. DriveQRecPtr CreateNewDriveQRecForPartition( UInt32 partitionID, UInt32 partitionSize, UInt32 partitionOffset )
  1212. {
  1213.     DriveQRecPtr    driveRec = nil;        // pointer to our volume record structure
  1214.     
  1215.     driveRec = CreateDriveQRecForPartition( partitionID, partitionSize, partitionOffset );
  1216.     if ( driveRec ) 
  1217.     {
  1218.         driveRec->driveNum = NextQDrive();        // assign a logical drive number
  1219.         NativeAddDrive( gOurDrvrRefNum, driveRec->driveNum,(DrvQElPtr)  &driveRec->driveStatus.qLink);
  1220.         driveRec->inDriveQ = true;
  1221.         
  1222.         return driveRec;
  1223.     }
  1224.     
  1225.     return driveRec;
  1226. }
  1227.  
  1228. //------------------------------------------------------------------------------
  1229. //    Function:        InstallDrive
  1230. //
  1231. //    Description:    Installs a physical drive and its volumes under the driver's
  1232. //                    control.  The driver determines if the drive is one it can
  1233. //                    manage, and if so, creates and initializes the drive's record,
  1234. //                    sets the drives operating mode and options, and mounts its
  1235. //                    partitions to the system.
  1236. //
  1237. //-------------------------------------------------------------------------------
  1238. void InstallDrive( DriveInstallCompletionProcPtr completionProc )
  1239. {
  1240.     //..............................................................................
  1241.     // Search for file system partitions on the media and install them as volumes
  1242.     // of this drive.  If no volumes, the drive must be considered unusable.
  1243.     UInt32    currentCapacity, currentBlockSize;
  1244.     Boolean    isWriteProtected;
  1245.     OSType    currentType;
  1246.     
  1247.     GetMediaProperties( ¤tCapacity,  ¤tBlockSize, &isWriteProtected, ¤tType ); 
  1248.  
  1249.     BlockZero((Ptr) &theInstallPB, sizeof(InstallPB));
  1250.     theInstallPB.capacity = currentCapacity;
  1251.     theInstallPB.blockSize = currentBlockSize;
  1252.     theInstallPB.currentMediaType = currentType;
  1253.     theInstallPB.installCompletion = completionProc;
  1254.     theInstallPB.useNativeBlocks = false;
  1255.     theInstallPB.currentState = kInstallStartState;
  1256.     ScanMediaForPartitions( (UInt32) &theInstallPB, noErr );
  1257. }
  1258.  
  1259.  
  1260. //------------------------------------------------------------------------------
  1261. //    Function:        EjectDrive
  1262. //    Description:    Removes a physical drive and its volumes from our control
  1263. //                    
  1264. //-------------------------------------------------------------------------------
  1265. void EjectDrive(DriveQRecPtr theDrivePtr)
  1266. {        
  1267.     if (theDrivePtr)                                // If the drive exists…
  1268.     {
  1269.         if( theDrivePtr->isPermanentQElement == false )
  1270.         {
  1271.             Dequeue((QElemPtr) &(theDrivePtr->driveStatus.qLink), GetDrvQHdr());    // remove from drive queue
  1272.         }
  1273.         
  1274.         FreeDriveQRec( theDrivePtr );
  1275.     }
  1276. }
  1277.  
  1278. //------------------------------------------------------------------------------
  1279. //    Function:        RemoveDrive
  1280. //    Description:    This is used to remove any Drive Queue element
  1281. //                    this includes our permanent queue element. 
  1282. //                    
  1283. //-------------------------------------------------------------------------------
  1284. void RemoveDrive(DriveQRecPtr theDrivePtr)
  1285. {        
  1286.     if (theDrivePtr)                                // If the drive exists…
  1287.     {
  1288.         Dequeue((QElemPtr) &(theDrivePtr->driveStatus.qLink), GetDrvQHdr());    // remove from drive queue        
  1289.     }
  1290.     
  1291.     FreeDriveQRec( theDrivePtr );
  1292. }
  1293.  
  1294. //------------------------------------------------------------------------------
  1295. //    Function:        IsDriveQueue1Free()
  1296. //
  1297. //    Description:    Returns true if drive queue element one is not in use,
  1298. //                    and returns false if it is.
  1299. //                    
  1300. //    Input:            none
  1301. //
  1302. //    Output:            Boolean
  1303. //-------------------------------------------------------------------------------
  1304. Boolean IsDriveQueueNumberFree( UInt16 driveNum )
  1305. {
  1306.     QHdrPtr    qhdr = GetDrvQHdr();                // Pointer to Drive Queue 
  1307.     DrvQEl    *qel = (DrvQEl*) (qhdr->qHead);        // Pointer to first element 
  1308.  
  1309.     while (qel)                                 // While not end of queue, 
  1310.     {
  1311.         if (qel->dQDrive == driveNum)             // check to see if drive number is in use 
  1312.         {
  1313.             return false;                        // drive number is in use, stop looking
  1314.         }
  1315.         else                                    // else next queue element
  1316.         {
  1317.             qel = (DrvQEl*) (qel->qLink);
  1318.         }
  1319.     }
  1320.  
  1321.     return true;                                // if we got here, drive number is free
  1322. }
  1323.  
  1324. //------------------------------------------------------------------------------
  1325. //    Function:        NextQDrive
  1326. //
  1327. //    Description:    Returns the next unused logical drive number from the system 
  1328. //                    Drive Queue.  The Drive Queue is searched starting with a
  1329. //                    logical drive number 8.
  1330. //                    
  1331. //    Input:            none
  1332. //
  1333. //    Output:            The highest Drive Queue drive number + 1
  1334. //-------------------------------------------------------------------------------
  1335. SInt16 NextQDrive( void )
  1336. {
  1337.     QHdrPtr    qhdr = GetDrvQHdr();                // Pointer to Drive Queue 
  1338.     DrvQEl    *qel = (DrvQEl*) (qhdr->qHead);        // Pointer to first element 
  1339.     SInt16    drv = 8;                            // Start above built in drives 
  1340.  
  1341.     while (qel)                                 // While not end of queue, 
  1342.     {
  1343.         if (qel->dQDrive == drv)                 // if drive number used, 
  1344.         {
  1345.             drv++;                                // bump number, and 
  1346.             qel = (DrvQEl*) (qhdr->qHead);        // search from start 
  1347.         }
  1348.         else                                    // else next queue element 
  1349.         {
  1350.             qel = (DrvQEl*) (qel->qLink);
  1351.         }
  1352.     }
  1353.  
  1354.     return drv;                                    // Return the next logical drive 
  1355. }
  1356.  
  1357. //------------------------------------------------------------------------------
  1358. //    Function:        UpdateQ
  1359. //    Description:    Updates the specified drive in the system drive queue with
  1360. //                    the specified capacity
  1361. //                    
  1362. //    Input:            qDrive:        the drive to update
  1363. //                    newSize:    the new drive capacity
  1364. //-------------------------------------------------------------------------------
  1365. void UpdateQ(SInt16 qDrive, SInt32 newSize)
  1366. {
  1367.     DriveQRecPtr    theDriveQ; 
  1368.     
  1369.     theDriveQ = FindDriveQRecForDriveNum( qDrive );
  1370.     if ( theDriveQ != nil )
  1371.     {
  1372.         DrvQEl *qel;
  1373.         
  1374.         qel = (DrvQEl *) &(theDriveQ->driveStatus.qLink);
  1375.         qel->dQDrvSz2         = newSize>>16;            // new capacity (hi word)
  1376.         qel->dQDrvSz         = newSize;                // low word of capacity 
  1377.         theDriveQ->partblks = newSize;                // save size for our use also
  1378.     }
  1379. }
  1380.  
  1381. //------------------------------------------------------------------------------
  1382. //    FUNCTION:    NextPartitionID
  1383. //    PURPOSE:    Returns the next unique partition ID for all volumes associated
  1384. //                with the specified drive.  NOTE: This function should be used only
  1385. //                when adding volumes which do not have a partition map on the media.
  1386. //                
  1387. //    INPUT:        drive:    pointer to the drive record to search for next partition ID
  1388. //
  1389. //    OUTPUT:        a unique partition ID related to the specified volume
  1390. //
  1391. //-------------------------------------------------------------------------------
  1392. SInt32 NextPartitionID( void )
  1393. {
  1394.     DriveQRecPtr     driveQ = nil;
  1395.     SInt32             nextPartitionID = 1;                // Start search with partition ID of 1
  1396.  
  1397.     driveQ = GetFirstDriveQRec();                        // first DriveQRec pointer
  1398.  
  1399.     while (driveQ)                                        // while not end of DriveQRec queue…
  1400.     {
  1401.         if (driveQ->partitionNo == nextPartitionID)        // if partition ID used
  1402.         {
  1403.             nextPartitionID++;                            // bump partition ID
  1404.             driveQ = GetFirstDriveQRec();                // reset DriveQRec pointer
  1405.         }
  1406.         else
  1407.         {
  1408.             driveQ = GetNextDriveQRec( driveQ );        // otherwise, point to next DriveQRec
  1409.         }
  1410.     }
  1411.     
  1412.     return nextPartitionID;                                // return number of next partition
  1413. }
  1414.  
  1415. //------------------------------------------------------------------------------
  1416. //    Function:        PostTheDiskInsertEvents
  1417. //    Description:    Post Disk Insert event for all partitions to be mounted
  1418. //
  1419. //    Input:            none
  1420. //
  1421. //    Output:            Returns any errors that occur from PostEvent
  1422. //-------------------------------------------------------------------------------
  1423. OSStatus PostTheDiskInsertEvents( void )
  1424. {
  1425.     DriveQRecPtr        driveRec;
  1426.     OSStatus            mountErr = noErr;
  1427.     
  1428.     // Post a Disk Inserted event for all HFS partitions not yet mounted
  1429.     driveRec = GetFirstDriveQRec();                                // first DriveQRec structure
  1430.     
  1431.     while (driveRec)                                             // for all partitions on drive…
  1432.     {    
  1433.         if ((driveRec->driveStatus.diskInPlace != 0) &&            // if media in place,
  1434.            (driveRec->mountPartition) &&                         // and partition should be mounted,
  1435.            (!driveRec->diskInsertPosted))                        // and hasn't been done yet
  1436.         {
  1437.             // This DriveQRec is marked as mountable, check if
  1438.             // PostEvents are turned on and if so issue one for this DriveQRec.
  1439.             if ( gDoPostEvents == true )
  1440.             {
  1441.                 mountErr = PostEvent(diskEvt, driveRec->driveNum);
  1442.             }
  1443.             else
  1444.             {
  1445.                 // PostEvents are turned off, return noErr because
  1446.                 // the application that turned the PostEvents off
  1447.                 // should handle mounting the appropriate drives.
  1448.                 mountErr = noErr;
  1449.             }
  1450.             
  1451.             if ( mountErr == noErr )
  1452.             {
  1453.                 driveRec->diskInsertPosted = true;
  1454.             }
  1455.         }
  1456.  
  1457.         driveRec = GetNextDriveQRec( driveRec );                            // next DriveQRec pointer
  1458.     }
  1459.  
  1460.     if ( mountErr != noErr )
  1461.     {
  1462.         // We should only get an error to PostEvent on boot,
  1463.         // Set our timer try again
  1464.         AbsoluteTime    theWait;
  1465.         
  1466.         theWait = DurationToAbsolute(durationSecond * 60);
  1467.         theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
  1468.         mountErr = SetInterruptTimer( &theWait, &RetryPostEventInterrupt, nil, &gPostEventTimer);
  1469.     }
  1470.     
  1471.     return mountErr;                                                // return error if one occurred
  1472. }
  1473.  
  1474. OSStatus RetryPostEventInterrupt( void *p1, void *p2)
  1475. {
  1476. #pragma unused ( p1, p2 )
  1477.     gPostEventTimer = 0;
  1478.     
  1479.     (void) PostTheDiskInsertEvents();
  1480.     return noErr;
  1481. }
  1482.  
  1483. #pragma mark --
  1484. #pragma mark Volume Related Routines
  1485. //------------------------------------------------------------------------------
  1486. //    Function:        IsVolumeMountedForDrive
  1487. //    Description:    Searches the volume queue for a mounted volume specified 
  1488. //                    by vRefNum.  If one is found, true is returned.
  1489. //                    
  1490. //    Input:            driveNum:    the volume reference to search for
  1491. //
  1492. //    Output:            true if volume mounted, else false
  1493. //-------------------------------------------------------------------------------
  1494. Boolean IsVolumeMountedForDrive( UInt16 driveNum )
  1495. {
  1496.     QHdrPtr    volQ = LMGetVCBQHdr();     // VCB queue head pointer
  1497.     VCBPtr    theVol;                    // first VCB
  1498.  
  1499.     if ( volQ == nil )
  1500.     {
  1501.         theVol = nil;
  1502.     }
  1503.     else
  1504.     {
  1505.         theVol = (VCBPtr) volQ->qHead;
  1506.     }
  1507.  
  1508.     while( theVol != nil )
  1509.     {
  1510.         // The test for whether a volume is mounted or not is done using
  1511.         // the VCB fields vcbDrvNum and vcbDRefNum.  A volume is mounted
  1512.         // only if it is online.
  1513.         // 
  1514.         //                    online            offline            ejected
  1515.         // 
  1516.         //    vcbDrvNum        >0 (DrvNum)         0                 0
  1517.         //    vcbDRefNum        <0 (DRefNum)    <0 (-DrvNum)    >0 (DrvNum)
  1518.     
  1519.         if (theVol->vcbDrvNum == driveNum)    // if volume specified is online…
  1520.         {
  1521.             return true;                    // volume is mounted
  1522.         }
  1523.         
  1524.         theVol = (VCBPtr) theVol->qLink;    // next VCBPtr
  1525.     }
  1526.     
  1527.     // There is no volume mounted for the requested driveNum.
  1528.     return false;
  1529. }
  1530.  
  1531. #pragma mark --
  1532. #pragma mark Partition Format Related Routines
  1533. //------------------------------------------------------------------------------
  1534. //    Function:        ConvertToUC
  1535. //    Description:    Converts the input ASCII character to its upper if possible.
  1536. //                    Character range is a…z
  1537. //                    
  1538. //    Input:            theCharacter:    character to be converted
  1539. //    Output:            the upper case of the character if possible, else the character
  1540. //-------------------------------------------------------------------------------
  1541. static UInt8         ConvertToUC(UInt8 theCharacter);
  1542.  
  1543. UInt8 ConvertToUC(UInt8 theCharacter)
  1544. {
  1545.     if ((theCharacter >= 'a') && (theCharacter <= 'z'))    // a lower case character?
  1546.         return(theCharacter & 0xDF);    // if so, convert to upper case
  1547.     else
  1548.         return(theCharacter);            // if not, return as is
  1549. }
  1550.  
  1551. //------------------------------------------------------------------------------
  1552. //    Function:        GetPartitionType
  1553. //    Description:    This function determines the partition type.  Following parti- 
  1554. //                    tion types are recognized:  
  1555. //                    • Apple driver partition
  1556. //                    • HFS partition 
  1557. //                    • Apple partition map, Apple Free, and Apple Scratch
  1558. //                    If an unknown type is detected, the function returns ISADDTOQUEUE
  1559. //                    file system ID to be handled by someone else above.
  1560. //                    
  1561. //    Input:            A pointer to a partition: pm *
  1562. //
  1563. //    Output:            Returns true if this partion should be mounted
  1564. //
  1565. //-------------------------------------------------------------------------------
  1566. Boolean ShouldPartitionBeMounted(Partition* thePartition )
  1567. {
  1568.     SInt16 i,j;
  1569.     static char *knownPartitionTypes[] = {
  1570.         "APPLE_DRIVER43",
  1571.         "APPLE_HFS",
  1572.         "APPLE_PARTITION_MAP",
  1573.         "APPLE_FREE",
  1574.         "APPLE_SCRATCH",
  1575.         "APPLE_PRODOS",
  1576.         "APPLE_DRIVER_ATA",
  1577.         "APPLE_PATCHES",
  1578.         "APPLE_UNIX_SVR2"
  1579.     };
  1580.  
  1581.     // The following defines refer to the items in knownPartitionTypes. 
  1582. #define POS_BEGIN 0
  1583. #define POS_APPLE_DRIVER 0
  1584. #define POS_APPLE_HFS 1
  1585. #define POS_APPLE_PRODOS 5
  1586. #define    POS_APPLE_ATADRIVER    6
  1587. #define POS_END 8
  1588.  
  1589.     // First check to see if we recognize one of the known partitions. 
  1590.     for (j = POS_BEGIN; j <= POS_END; j++) 
  1591.     {
  1592.         char *knownPartitionTypePtr;
  1593.         
  1594.         i = 0;
  1595.         knownPartitionTypePtr = knownPartitionTypes[j];
  1596.         while (knownPartitionTypePtr[i] == ConvertToUC (thePartition->pmParType[i]))
  1597.         {
  1598.             if (knownPartitionTypePtr[i++] == '\0')        // We found one that we recognize. 
  1599.             {
  1600.                 switch(j) 
  1601.                 {
  1602.                     case POS_APPLE_HFS:
  1603.                     case POS_APPLE_PRODOS:
  1604.                     {
  1605.                         return true;
  1606.                     }
  1607.                     break;
  1608.     
  1609.                     default:
  1610.                     {
  1611.                         // We must have found one of the ones that can't be mounted. 
  1612.                         return false;
  1613.                     }
  1614.                     break;
  1615.                 }
  1616.             }
  1617.         }
  1618.     }
  1619.     
  1620.     // None matched.  Now see if we shouldn't add this to the queue. 
  1621.     return false;
  1622. }
  1623.